package alkaid.eis.schedule.core;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;

import alkaid.eis.common.util.ExceptionHelper;
import alkaid.eis.schedule.domain.JobInfo;
import alkaid.eis.schedule.domain.JobInfo.State;
import alkaid.eis.schedule.domain.JobInfoRepository;
import alkaid.eis.schedule.domain.JobLog.Level;
import alkaid.eis.schedule.domain.JobService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 任务注册
 * 
 * @author Lucky Yang
 * @since 0.0.1
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class CronTaskRegistrar implements DisposableBean {

    private final Map<Long, ScheduledFuctureHolder> scheduledTaskMap = new ConcurrentHashMap<>(16);

    private final TaskScheduler taskScheduler;
    private final JobService jobService;
    private final JobInfoRepository jobInfoRepository;

    public void addTask(JobInfo jobInfo) {
        SchedulingTask task = new SchedulingTask(jobInfo.getId(), jobService, jobInfoRepository);
        addTask(task);
    }

    protected void addTask(SchedulingTask task) {
        if (task == null) {
            return;
        }

        JobInfo jobInfo = jobService.findInfoById(task.jobInfoId);
        try {
            jobService.updateInfoState(jobInfo, State.STARTED);
            if (this.scheduledTaskMap.containsKey(jobInfo.getId())) {
                log.warn("任务已经存在，不能添加：{}", jobInfo);
                return;
            }

            CronTask cronTask = new CronTask(task, jobInfo.getCronExpression());
            ScheduledFuture<?> future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
            this.scheduledTaskMap.put(task.jobInfoId, new ScheduledFuctureHolder(task, future));

            jobService.createLog(jobInfo, Level.STARTED, task.formatMessage("启动任务"));
        } catch (Exception e) {
            jobService.updateInfoState(jobInfo, State.STOPPED);
            jobService.createLog(jobInfo, Level.ERROR, task.formatMessage(ExceptionHelper.stacktraceToString(e)));
        }

    }

    public boolean containTask(Long jobInfoId) {
        return scheduledTaskMap.containsKey(jobInfoId);
    }

    public void removeCronTask(Long jobInfoId) {
        ScheduledFuctureHolder hoder = this.scheduledTaskMap.remove(jobInfoId);
        if (hoder != null) {
            hoder.cancelTask();
        }
    }

    @Override
    public void destroy() {
        for (ScheduledFuctureHolder hoder : this.scheduledTaskMap.values()) {
            hoder.cancelTask();
        }

        this.scheduledTaskMap.clear();
    }

}
